package net.maku.framework.beansearcher;

import cn.hutool.core.util.StrUtil;
import cn.zhxu.bs.SearchSql;
import cn.zhxu.bs.SqlInterceptor;
import cn.zhxu.bs.param.FetchType;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import net.maku.framework.common.constant.Constant;
import net.maku.framework.security.user.SecurityUser;
import net.maku.framework.security.user.UserDetail;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * 数据权限拦截器
 * @author Troy.Zhou @ 2024-11-06
 */
@Component
public class DataScopeSqlInterceptor implements SqlInterceptor {

    @Override
    public <T> SearchSql<T> intercept(SearchSql<T> searchSql, Map<String, Object> paraMap, FetchType fetchType) {
        DataScope scope = searchSql.getBeanMeta().getBeanClass().getAnnotation(DataScope.class);
        if (scope == null) {
            return searchSql;   // 如果没有启用数据权限，则直接返回
        }
        searchSql.setListSqlString(process(scope, searchSql.getListSqlString()));
        searchSql.setClusterSqlString(process(scope, searchSql.getClusterSqlString()));
        return searchSql;
    }

    static final String PLACEHOLDER = "<ds>";   // 占位符

    private String process(DataScope scope, String sql) {
        int index = sql.indexOf(PLACEHOLDER);
        if (index < 0) {
            return sql;         // 没有占位符，直接返回
        }
        String preSql = sql.substring(0, index);
        String nexSql = sql.substring(index + PLACEHOLDER.length());
        UserDetail user = SecurityUser.getUser();
        if (user == null) {
            throw new IllegalStateException("用户未登录，代码不应该执行到此，请检查接口的权限保护策略是否有漏洞！");
        }
        String scopeSql = buildScopeSql(scope, user);
        if (scopeSql == null) {
            return preSql + nexSql;
        }
        String trim = preSql.trim().toLowerCase();
        if (trim.endsWith("where") || trim.endsWith("and")) {
            return preSql + " " + scopeSql + " " + nexSql;
        }
        return preSql + " and " + scopeSql + " " + nexSql;
    }

    private String buildScopeSql(DataScope scope, UserDetail user) {
        if (user.getSuperAdmin().equals(Constant.SUPER_ADMIN)) {
            return null;
        }
        List<Long> orgIds = user.getDataScopeList();
        if (orgIds == null) {
            return null;
        }
        StringBuilder scopeSql = new StringBuilder("(");
        if (!orgIds.isEmpty()) {
            scopeSql.append(concat(scope.on(), scope.orgId()))
                    .append(" in (").append(StrUtil.join(",", orgIds)).append(")")
                    .append(" or ");
        }
        scopeSql.append(concat(scope.on(), scope.ownerId()))
                .append(" = ").append(user.getId())
                .append(")");
        return scopeSql.toString();
    }

    private String concat(String on, String field) {
        if (StringUtils.isBlank(on)) {
            return field;
        }
        return on + "." + field;
    }

}
